AI-powered smart commit message generator for coding agents
- Multi-Provider Support: Supports Antigravity CLI (
agy, the successor of Gemini CLI), Codex CLI, Claude Code, opencode, and Apple Intelligence with automatic fallback. The same provider can appear multiple times with different models or accounts (see "Advanced: Provider Fallback Chain" below). - Smart Cooldown: Automatically demotes failed steps for 1 hour (configurable), keyed per provider+model+account so one rate-limited account or model does not block the others
- Format Detection: Detects commit format from recent commits (Conventional, Bracket, Emoji, etc.)
- Empty Repo Safe: Auto format detection falls back cleanly even when the repository has no commits and Git outputs localized messages
- Interactive: Prompts for confirmation before committing (skip with
-y) - Dry Run: Preview generated messages without committing (
-n) - Quiet Mode: Suppresses progress output for hook/scripting use (
-q) - Body Support: Generate detailed commit messages with bullet points (
-b) - Amend/Squash/Reword: Regenerate messages for existing commits
- Private Temp Files: AI prompts, Codex final-output files, and reword message files are created without group/other read permissions on Unix/macOS
- Agent Context: Integrates with claw-hooks to generate context-aware messages reflecting the agent's intent
- OS: macOS, Linux, Windows
- Git: Required
- AI Provider (at least one):
- Antigravity CLI (
agy, successor of Gemini CLI): see https://antigravity.google/docs/gcli-migration (the legacy Gemini CLI stops serving requests on 2026-06-18) - Codex CLI:
npm install -g @openai/codex - Claude Code:
curl -fsSL https://claude.ai/install.sh | bash - opencode:
curl -fsSL https://opencode.ai/install | bash - Apple Intelligence: Built-in on macOS (macOS 26+ with Apple Silicon required)
- Antigravity CLI (
brew install owayo/git-sc/git-scgit clone https://github.com/owayo/git-smart-commit.git
cd git-smart-commit
make installDownload the latest binary from Releases.
curl -L https://github.com/owayo/git-smart-commit/releases/latest/download/git-sc-aarch64-apple-darwin.tar.gz | tar xz
sudo mv git-sc /usr/local/bin/curl -L https://github.com/owayo/git-smart-commit/releases/latest/download/git-sc-x86_64-apple-darwin.tar.gz | tar xz
sudo mv git-sc /usr/local/bin/curl -L https://github.com/owayo/git-smart-commit/releases/latest/download/git-sc-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv git-sc /usr/local/bin/curl -L https://github.com/owayo/git-smart-commit/releases/latest/download/git-sc-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv git-sc /usr/local/bin/Download git-sc-x86_64-pc-windows-msvc.zip from Releases, extract, and add to PATH.
# Generate commit message for staged changes
git-sc
# Stage all and commit without confirmation
git-sc -a -y
# Preview message (dry run)
git-sc -n| Command | Description |
|---|---|
git-sc |
Generate message for staged changes |
git-sc init |
Initialize configuration file |
git-sc -a |
Stage all changes and generate message |
git-sc --amend |
Regenerate message for last commit |
git-sc --squash <BASE> |
Squash all commits into one |
git-sc --reword <HASH> |
Regenerate message for specific commit |
git-sc -g <HASH> |
Generate from existing commit (output only) |
| Option | Short | Description |
|---|---|---|
--yes |
-y |
Skip confirmation prompt |
--dry-run |
-n |
Show message without committing |
--all |
-a |
Stage all changes |
--body |
-b |
Generate with body (bullet points) |
| Option | Short | Description |
|---|---|---|
--amend |
Regenerate message for last commit | |
--squash |
Squash all commits into one | |
--reword |
Regenerate message for specific commit | |
--generate-for |
-g |
Generate from commit diff (output only) |
Operation modes (--amend, --squash, --reword, --generate-for) are mutually exclusive. Combining them fails during argument parsing instead of silently choosing one mode.
--amend note:
- Also works when the current
HEADis the root commit. - Preserves unrelated staged changes instead of folding them into the amended commit.
--reword note:
- Only accepts commits reachable from the current
HEADhistory. - Passing a hash from another branch (not in current history) fails with an error.
- Passing a merge commit hash also fails, even when the merge commit itself is the reword target.
- Rewording a commit that has a merge commit between it and
HEADis rejected with a clear "cannot reword across merge commits" error (merge-spanning reword is unsupported), rather than a confusing low-level git error such asfatal: ambiguous argument. - Rewording the oldest commit in current history is also supported (internally uses
git rebase -i --rootwhen required). - Rewording
HEADpreserves unrelated staged changes instead of folding them into the rewritten commit. - The internal rebase runs with
--no-autosquash, so a user-levelrebase.autoSquash = trueconfig cannot silently foldfixup!/squash!commits into the reworded commit.
--squash note:
- Fails before rewriting history when unrelated staged changes already exist. Commit, unstage, or stash them first.
- If the squash commit itself fails (e.g. rejected by a
pre-commit/commit-msghook or a GPG signing error), the branch is automatically restored to its originalHEADinstead of being left rewound at the merge-base.
| Option | Short | Description |
|---|---|---|
--provider |
-p |
Use specific AI provider (antigravity, codex, claude, opencode, apple-intelligence). The legacy name gemini is accepted as a backward-compatible alias for antigravity. |
--lang |
-l |
Override commit message language |
| Option | Short | Description |
|---|---|---|
--quiet |
-q |
Suppress progress messages |
--debug |
-d |
Show prompts sent to AI |
--help |
-h |
Print help |
--version |
-V |
Print version |
--quiet behavior:
- Suppresses progress, preview, and success/cancel messages in normal/amend/squash/reword flows
- Keeps error output visible
- In
--generate-formode, still prints only the generated commit message (for piping/scripting)
--debug behavior:
- In
--generate-formode, all debug output (config settings, AI prompt, provider command, streaming output) goes to stderr, so stdout remains the generated message only and stays safe to pipe
# Basic usage
git-sc # Generate for staged changes
git-sc -a -y # Stage all and commit directly
# Preview and body
git-sc -n # Dry run (preview only)
git-sc -b # Include detailed body
# Amend and squash
git-sc --amend # Regenerate last commit message
git-sc --squash origin/main # Squash feature branch commits
# Generate from existing commits
git-sc -g abc1234 # Generate from commit diff
git-sc -g abc1234 -b # With detailed bodyInitialize configuration with git-sc init, or create ~/.config/git-sc/config.toml manually:
git-sc initThis creates a configuration file with default settings at ~/.config/git-sc/config.toml.
Use --force to overwrite an existing configuration:
git-sc init --forcegit-sc supports hierarchical configuration with project-level overrides:
| File | Scope | Description |
|---|---|---|
~/.config/git-sc/config.toml |
Global | User-wide default settings |
.git-sc |
Project | Repository-specific overrides (in repo root) |
Project settings override global settings. Fields not specified in project config inherit from global config. You can specify only the fields you want to override — partial [models] sections are supported.
# AI provider priority
# "antigravity" is the successor of the legacy Gemini CLI (`agy` command).
# Writing "gemini" instead is still accepted as a backward-compatible alias.
providers = ["opencode", "antigravity", "codex", "claude", "apple-intelligence"]
# Commit message language
language = "Japanese"
# Commit prefix format (optional)
# Values: conventional, bracket, colon, emoji, plain, none
prefix_type = "conventional"
# Auto-push after commit (optional)
auto_push = true
# Codex reasoning effort passed via `-c model_reasoning_effort=<value>`
# Values: "low" (default), "medium", "high", "xhigh", or "" to omit and use codex default
codex_reasoning_effort = "low"
# Model configuration
# Antigravity CLI (`agy`) supports `--model`: the `antigravity` value is passed straight
# to `agy --model "<name>"`. Use the display name shown by `agy models`
# (e.g. "GPT-OSS 120B (Medium)", "Gemini 3.5 Flash (Low)"); an empty string omits
# `--model` and lets agy pick its own default. A legacy `gemini = "..."` key is still
# accepted as an input alias and is promoted to `antigravity` (an explicit `antigravity`
# value wins if both are present).
[models]
antigravity = "GPT-OSS 120B (Medium)"
codex = "gpt-5.4-mini"
claude = "haiku"
opencode = ""
# Provider cooldown (minutes)
provider_cooldown_minutes = 60
# Provider timeout (seconds) per call
provider_timeout_seconds = 60| Option | Description | Default |
|---|---|---|
providers |
Provider fallback chain — each entry is a provider name string or a {provider, model, command, env, name} table (see "Advanced: Provider Fallback Chain" below; antigravity recommended, gemini accepted as an alias) |
["opencode", "antigravity", "codex", "claude", "apple-intelligence"] |
language |
Commit message language | "Japanese" |
prefix_type |
Commit prefix format | Auto-detect |
auto_push |
Auto-push after commit | false |
codex_reasoning_effort |
Codex -c model_reasoning_effort value (low, medium, high, xhigh, or "" to omit) |
"low" |
models.* |
Model for each provider | See config |
provider_cooldown_minutes |
Failed provider cooldown; extremely large values are treated as effectively indefinite | 60 |
provider_timeout_seconds |
Provider call timeout | 60 |
prefix_rules |
URL-based prefix format | [] |
prefix_scripts |
External prefix scripts | [] |
Existing global config files are not rewritten automatically. The current Codex default is gpt-5.4-mini; to use it in an existing setup, update models.codex in ~/.config/git-sc/config.toml. This default was reselected on June 9, 2026 (JST) by comparing input_tokens for Codex models that are API-visible, listed, and support medium reasoning, and re-verified on June 26, 2026 (JST). The latest measurement used Reply ok. in an empty directory with --ignore-user-config --ignore-rules --ephemeral --sandbox read-only and model_reasoning_effort='medium': gpt-5.5 = 17651, gpt-5.4 = 16266, gpt-5.4-mini = 15912. All accepted runs produced ok and no tool calls, so the ranking is stable and the default is unchanged.
The default Antigravity (agy) model is GPT-OSS 120B (Medium). agy 1.0.x print mode currently exposes no official --json / --output option for per-request token usage, so an input_tokens comparison like Codex's is not possible. Re-verified June 26, 2026 (JST) with agy 1.0.12: agy models lists Gemini 3.5 Flash (Medium/High/Low), Gemini 3.1 Pro (Low/High), Claude Sonnet 4.6 (Thinking), Claude Opus 4.6 (Thinking), and GPT-OSS 120B (Medium) — unchanged from the June 25, 2026 candidate set. Google Cloud Agent Platform pricing lists gpt-oss-120b at $0.09 / 1M input tokens, lower than the listed Gemini and Claude alternatives, so this remains the lowest input-price default among the CLI-provided models. To use it in an existing setup, add or update models.antigravity in ~/.config/git-sc/config.toml, or set it to "" to defer to agy's own default.
Provider cooldown state normalizes legacy aliases before reordering providers, so gemini/agy cooldown entries still apply to antigravity, and legacy apple-ai / apple_intelligence entries still apply to apple-intelligence. Running with --debug also prints a one-time notice when a legacy gemini provider alias is found in your config, reminding you that it is normalized to antigravity.
Each entry in providers can be either a plain string (provider name only) or a table that also specifies model, command, and env. This lets you build a fallback chain where the same provider appears multiple times with different models or accounts — useful when one provider splits its quota per model family or per account/contract.
providers = [
# Same provider, different accounts (switch via env: CODEX_HOME / CLAUDE_CONFIG_DIR).
{ provider = "codex", model = "gpt-5.4-mini", env = { CODEX_HOME = "~/.codex" } }, # account 1
{ provider = "codex", model = "gpt-5.4-mini", env = { CODEX_HOME = "~/.codex-work" } }, # account 2
# Same provider, different model families (separate quotas).
{ provider = "antigravity", model = "Gemini 3.5 Flash (Low)" },
{ provider = "antigravity", model = "GPT-OSS 120B (Medium)" },
# A plain string is still accepted (provider name only).
"claude",
]Per-step fields:
| Field | Description |
|---|---|
provider |
Required. Provider type that decides the CLI argument convention (codex, antigravity, claude, opencode, apple-intelligence; gemini/agy accepted as aliases). |
model |
Optional. Model for this step. If omitted, falls back to [models].<provider>, then the CLI's own default. |
command |
Optional. Executable (and fixed args) to run instead of the provider's default binary — e.g. a wrapper script. ~ is expanded. The provider's standard arguments (--disable hooks etc. for codex) are still applied. |
env |
Optional. Environment variables set explicitly via Command::env() when launching this step. ~ in values is expanded; the key must be a valid POSIX name. Dynamic-loader / interpreter pre-load keys (LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS, PYTHONPATH etc.) are rejected case-insensitively with a config error to prevent code-injection via project-level .git-sc. |
name |
Optional. Identifier used for the cooldown key and log label. If omitted, it is derived deterministically from provider + model + env + command. |
Account switching (recommended: env). Codex and Claude Code pick their account/credentials from CODEX_HOME / CLAUDE_CONFIG_DIR. Setting these per step via env lets you fall back across accounts, each with its own quota. git-sc applies them with an explicit Command::env() override, so the launched CLI is not affected by whatever CODEX_HOME / CLAUDE_CONFIG_DIR happens to be exported in the shell that runs git-sc. (A wrapper script via command works too, but env is preferred because it is explicit and shown in --debug.)
Independent cooldown. The cooldown key includes provider + model + env (+ command, or an explicit name), so each step is demoted independently: if codex on account 1 hits a rate limit, codex on account 2 — and antigravity on a different model — stay available.
| Value | Example | Description |
|---|---|---|
conventional |
feat: add feature |
Conventional Commits format |
bracket |
[feat] add feature |
Bracket-style prefix |
colon |
feat: add feature |
Simple colon prefix |
emoji |
:sparkles: add feature |
Emoji prefix |
plain |
Add feature |
No prefix |
none |
add feature |
No prefix, lowercase |
Specify commit format by remote URL:
[[prefix_rules]]
url_pattern = "github\\.com[:/]myorg/"
prefix_type = "conventional" # conventional, bracket, colon, emoji, plainCustom prefix generation via external scripts:
[[prefix_scripts]]
url_pattern = "^https://gitlab\\.example\\.com/"
script = "/path/to/prefix-generate.py"If a prefix script returns a valid prefix_type name (e.g. conventional, bracket, emoji, etc.) instead of a literal prefix string, git-sc interprets it as a Rule mode. This allows scripts to dynamically select the commit format based on branch name or remote URL.
For literal prefix strings, trailing line endings (\n/\r\n) from common script output such as echo are removed, while intentional trailing spaces are preserved.
If a prefix script returns empty output (exit 0 with no text), git-sc keeps the generated message as-is, except it removes a leading Conventional Commit type prefix (for example feat:, fix(scope):, feat!:) when present.
If a prefix script exits with code 1, git-sc keeps the AI-generated message without adding a prefix. Other non-zero exit codes are treated as script execution failures, so git-sc falls back to the next matching prefix script, prefix rule, configured prefix_type, or auto detection.
For project-level .git-sc, relative script paths are resolved from the Git repository root, and the script runs with the Git root as its working directory.
#!/bin/bash
# Example: return "conventional" to use Conventional Commits format
echo "conventional"- Whitespace-only changes excluded
- Binary files excluded
- Quoted diff headers with spaces or non-ASCII file paths are handled correctly
.git-sc-ignorepatterns applied- Truncated at 10,000 characters
- AI prompts may contain staged diff content. When git-sc needs a temporary prompt file for providers such as opencode, or a final-output file for Codex, it creates the file with no group/other permissions on Unix/macOS and removes it automatically after use.
- Reword message temporary files use the same private-file behavior.
Patterns are matched against the decoded Git path, so quoted diff headers such as Japanese filenames escaped by Git are excluded correctly as well.
Rename diffs are checked against both the source path and destination path, so moving a file into an ignored directory is excluded consistently too.
Filenames containing spaces are also supported: Git does not quote space-only filenames in diff --git headers, but git-sc still extracts the correct path so that ignore patterns apply consistently.
This also covers rename headers where the source and destination paths differ and both paths contain spaces, as well as mixed headers where only one side is quoted (e.g. renaming old name.txt to a non-ASCII filename that Git quotes).
package-lock.json
yarn.lock
Cargo.lock
*.generated.tsEnable auto-push in your config file:
# In ~/.config/git-sc/config.toml or .git-sc
auto_push = trueWhen enabled, git-sc will run git push after a successful commit or squash.
Git-SC (Smart Commit) - Available on VS Code Marketplace
Add to ~/.claude/settings.json:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "git-sc --all --yes --quiet"
}
]
}
]
}
}When git-sc is used with claw-hooks, it automatically receives context about what the coding agent was working on via the CLAW_HOOKS_AGENT_MESSAGE environment variable. This context is included in the AI prompt, enabling the generated commit message to reflect the high-level intent rather than just describing the raw diff.
claw-hooks is a companion tool that manages Claude Code's hook lifecycle. When its stop hook fires, it sets CLAW_HOOKS_AGENT_MESSAGE with the agent's last activity summary before invoking git-sc.
# Automatically set by claw-hooks stop hook
# CLAW_HOOKS_AGENT_MESSAGE="Refactored authentication to use JWT tokens"
git-sc -a -y -qWhen the environment variable is set, the prompt includes an "Agent Context" section that guides the AI to prioritize the developer's intent.
This applies to standard commit generation as well as --amend, --reword, --squash, and --generate-for.
flowchart LR
A[Stage Changes] --> B[Get Diff]
B --> C[Detect Format]
C --> D[Generate via AI]
D --> E[Confirm & Commit]
- Verify: Check git repo and AI agent availability
- Config: Load
~/.config/git-sc/config.tomlsettings - Diff: Get staged changes (with exclusions)
- Format: Detect from recent commits or rules
- Generate: Send to AI with fallback
- Commit: Confirm and create commit
Apple Intelligence provider uses fm-rs (Rust bindings for Apple's Foundation Models framework) for fully on-device inference. No API key or network connection is required.
- Requirements: macOS 26 (Tahoe) or later, Apple Silicon, Apple Intelligence enabled in System Settings
- How it works: With Apple Intelligence enabled (default on macOS), git-sc calls Foundation Models directly via fm-rs. A
LanguageModelSessionis created with commit-message-specific instructions for each generation. The instructions are built from the resolved prefix type, soprefix_type = "none"/"bracket"/"emoji"and auto-detection from recent commits are respected instead of always forcing Conventional Commits. - Build:
cargo build --features apple-ai(automatic withmake build/make installon macOS) - Cross-platform: On Linux/Windows, Apple Intelligence is not available and is automatically skipped
- Windows: the Antigravity CLI (
agy) provider is skipped with an explicit error. All providers launch throughcmd /Con Windows (to support npm-installed.cmdshims), but cmd.exe cannot safely receive a multi-line diff prompt as a command-line argument, so passing it would corrupt the command (and is a known command-injection vector class, CVE-2024-24576). The fallback chain simply moves on to the next provider. Providers that read the prompt from stdin or a temp file (codex, claude, opencode) are unaffected.
| Command | Description |
|---|---|
make build |
Build debug version |
make release |
Build release version |
make install |
Build and install to /usr/local/bin |
make test |
Run tests |
make fmt |
Format code |
make check |
Run clippy and cargo check (includes apple-ai on macOS) |
make clean |
Clean build artifacts |
Contributions are welcome! Please feel free to submit a Pull Request.
See Releases for version history.
